
import java.rmi.RemoteException;
import java.util.*;
import java.awt.Point;

public class PlayerData implements PlayerListener {
	
	private Group heldCards = new Group();	//cards controlled by selector
	private Group selectedCards = new Group();	//selected cards: may or may not contain some or all of held cards
	private Player player;
	private CardsServer cardsServer;
	
	//array of card id's for sending over network
	int[] selectedCardIds;
	
	
	//put this in table panel when lock is available
	private static int snapX = 15;
	private static int snapY = 25;
	private static int snapRatio = 4;
	private boolean snap = true;
	
	
	public PlayerData(Player p, CardsServer cs){
		player = p;
		cardsServer = cs;
		player.alert();
	}
	
/**
	The <code>Player</code> takes control the selected cards.
	*/
	public void hold() {
		ArrayList<Card> cardsLeftToPlace = new ArrayList<Card>(selectedCards);
		ZComparator.sort(cardsLeftToPlace);
		while (!cardsLeftToPlace.isEmpty()) {
			Card c = cardsLeftToPlace.remove(0);
			//fix z
			c.setZ(findHighestZ(c,cardsLeftToPlace) + 1);
		}
		player.alert();
		updateServer();
	}
	
	/**
	The <code>Player</code> relinquishes control of the selected cards.
	*/
	public void release(){
		
		for(Card card: selectedCards) {
			int x = card.getLocation().x;
			int y = card.getLocation().y;
			
			if(snap == true) {
				if(x % snapX > snapX / 2) {
					
					if(y % snapY > snapY / 2) {
						card.setLocation(x + (snapX - x % snapX),  y + (snapY - y % snapY));
					} else {
						card.setLocation(x + (snapX - x % snapX),  y - (y % snapY));
					}
				
				} else {
					
					if(y % snapY > snapY / 2) {
						card.setLocation(x - (x % snapX),  y + (snapY - y % snapY));
					} else {
						card.setLocation(x - (x % snapX), y - (y % snapY));
					}
				}
			} else {
				card.setLocation(x, y);
			}
		}
		
		player.alert();
		updateServer();
	}
	
	public void setSnap(boolean s) {
		snap = s;
	}
	
	//////// the following methods should only be called when player does not have control.
	
	public void select(Set<Card> cards) {
		selectedCards = (Group)cards;
		selectedCardIds = new int[cards.size()];
		int i = 0;
		
		for (Card c: cards) {
			selectedCardIds[i++] = c.getID();
		}
	}
	
	
	//////// the following methods should only be called when player has control.
	
	/**
	The player drops some of the cards they are currently controlling.
	*/
	public void dropSelection(Set<Card> cards) {
		heldCards.removeAll(cards);
	}
	
	/**
	The <code>Player</code> moves the selected cards.  Must be preceded by a call to <code>pickUp</code>.
	@param point the amount to offset the cards by.
	*/
	public void moveBy(Point point){
		int dx = point.x;
		int dy = point.y;
		
		ArrayList<Card> cardsLeftToPlace = new ArrayList<Card>(selectedCards);
		ZComparator.sort(cardsLeftToPlace);
		while (!cardsLeftToPlace.isEmpty()) {
			Card c = cardsLeftToPlace.remove(0);
			Point oldLoc = c.getLocation();
			c.setLocation(new Point(oldLoc.x + dx, oldLoc.y + dy));
			//fix z
			c.setZ(findHighestZ(c,cardsLeftToPlace) + 1);
		}
		
		player.alert();
		//updateServer();
		cardsServer.moveBy(point);
	}
	
	public void flip() {
		System.out.println("Flip - " + selectedCards.toString());
		
		if (selectedCards.isEmpty()) {
			return;
		}
		for (Card c: selectedCards) {
			c.toggleFaceUp();
		}
		player.alert();
		//updateServer();
		cardsServer.flip();
	}
	
	public Table getTable() {
		return cardsServer.getTable();
	}
	
	public boolean isSelectedCard(Card card) {
		return selectedCards.contains(card);
	}
	
	public int findHighestZ(Card selected) {
		return findHighestZ(selected, new ArrayList<Card>());
	}
	
	/**
	 * Calculates the highest Z-index of all cards intersecting with a given {@link Card}.
	 * 
	 * @param selected The selected <code>Card</code>.
	 * @param except do not count these cards' z value, when finding the highest value.  <code>selected</code> will be automatically considered to be in this group.
	 * @return The highest Z-index found.
	 */
	private int findHighestZ(Card selected, List<Card> except) {
		
		List<Card> cards = getRoom().getTable().getDeck().getDeck();
		int highestZ = 0;
	
		for(Card card: cards){
			
			if(except.contains(card)) continue;
			if(selected == card) continue;
			
			if(selected.getRectangle().intersects(card.getRectangle())){//intersects with point
				if(card.getZ() > highestZ){//check if highest z
					highestZ = card.getZ();//set c and z
				}
			}
		}
		
		//System.out.println("z " + (highestZ + 1));
		return highestZ;
	}
	
	private Room getRoom() {
		return cardsServer.getRoom();
	}
	
	private void updateServer(){
		cardsServer.updateServer();
	}
	

	public int[] getSelectedCardIds() {
		return selectedCardIds;
	}
	
	public void shuffle(){
		selectedCards.shuffle();
		updateServer();
	}
	
	// set permissions on cards
	//public void setViewPermissions...

//rememba set of cards
//copy sum out of model.java
}
